﻿#ifndef __INC_KH_COMPILER_H__
#define __INC_KH_COMPILER_H__

#ifdef _MSC_VER
#pragma once
#endif

//////////////////////////////////////////////////////////////////////////
// declaration

// token
enum khTokenType
{
	KHTKT_UNKNOWN,
	KHTKT_IDENTIFIER,
	KHTKT_CONSTANT,
	KHTKT_ARG,
	KHTKT_DECL,
	KHTKT_STMT,
	KHTKT_EXPR,
	KHTKT_OP,
	KHTKT_KEYWORD,
	KHTKT_RESERVED,

	KHTKT_MAX_VALUE
};

// token role
enum khTokenRole
{
	KHTKR_UNKNOWN,

	// 식별자 IDENTIFIER
	KHTKR_ID_UNKNOWN,
	KHTKR_ID_PUBLIC,
	KHTKR_ID_SELF,
	KHTKR_ID_LOCAL,

	// 상수 CONST
	KHTKR_CONST_NULL,
	KHTKR_CONST_BOOL,
	KHTKR_CONST_INT,
	KHTKR_CONST_LONG,
	KHTKR_CONST_FLOAT,
	KHTKR_CONST_DOUBLE,
	KHTKR_CONST_STRING,
	KHTKR_CONST_WIDESTRING,

	// 인수 ARG
	KHTKR_ARG_VARG,
	KHTKR_ARG_DECL,
	KHTKR_ARG_DECO,

	// 선언 DECL
	KHTKR_DECL_PUBLIC,
	KHTKR_DECL_SELF,
	KHTKR_DECL_LOCAL,

	// 문법 STMT
	KHTKR_STMT_COMPOUND,
	KHTKR_STMT_RETURN,
	KHTKR_STMT_FUNCTION,
	KHTKR_STMT_IF,
	KHTKR_STMT_WHILE,
	KHTKR_STMT_DO,
	KHTKR_STMT_FOR,
	KHTKR_STMT_FOREACH_DBL,
	KHTKR_STMT_FOREACH_SGN,
	KHTKR_STMT_SWITCH,
	KHTKR_STMT_CASE,
	KHTKR_STMT_DEFAULT,
	KHTKR_STMT_CONTINUE,
	KHTKR_STMT_BREAK,
	KHTKR_STMT_LABEL,
	KHTKR_STMT_GOTO,
	KHTKR_STMT_LINE,
	KHTKR_STMT_BREAKPOINT,
	KHTKR_STMT_SUSPEND,

	// 수식 EXPR
	KHTKR_EXPR_SELF,
	KHTKR_EXPR_TABLE,
	KHTKR_EXPR_ARRAY,
	KHTKR_EXPR_FUNCTION,
	KHTKR_EXPR_CALL,

	// 연산 OP
	KHTKR_OP_ASSIGN,
	KHTKR_OP_ASSIGN_FIELD,
	KHTKR_OP_ASSIGN_INDEX,
	KHTKR_OP_UNARY_PLUS,
	KHTKR_OP_UNARY_MINUS,
	KHTKR_OP_UNARY_NOT,
	KHTKR_OP_UNARY_SIG,
	KHTKR_OP_UNARY_INC,
	KHTKR_OP_UNARY_DEC,
	KHTKR_OP_MUL,
	KHTKR_OP_DIV,
	KHTKR_OP_MOD,
	KHTKR_OP_ADD,
	KHTKR_OP_SUB,
	KHTKR_OP_SHL,
	KHTKR_OP_SHR,
	KHTKR_OP_LT,
	KHTKR_OP_LE,
	KHTKR_OP_EQ,
	KHTKR_OP_NEQ,
	KHTKR_OP_BINARY_AND,
	KHTKR_OP_BINARY_XOR,
	KHTKR_OP_BINARY_OR,
	KHTKR_OP_AND,
	KHTKR_OP_OR,
	KHTKR_OP_INC,
	KHTKR_OP_DEC,
	KHTKR_OP_INDEX,
	KHTKR_OP_DOT,
	KHTKR_OP_SIZEOF,
	KHTKR_OP_TYPENAME,
	KHTKR_OP_NEW,

	// 키워드
	KHTKR_KW_DONOTUSETHIS,

	// 노드 요소
	KHTKR_ROLE_MAX_VALUE
};

// token flag
enum khTokenFlag
{
	KHTKF_EXPR_SELF = 0x0001,
	KHTKF_EXPR_PARENT = 0x0002,
	KHTKF_DUP = 0x0004,
	KHTKF_SYMBOL = 0x0008,
	KHTKF_RARL = 0x0010
};


//////////////////////////////////////////////////////////////////////////
// tokenize -> parse -> compile

//
struct kRedFn;

//
typedef struct khToken
{
	enum khTokenType	type;
	enum khTokenRole	role;
	enum khTokenFlag	flags;

	union
	{
		klong			i64;
		double			dbl;
		kchar*			str;
		kwchar*			wcs;
		kpointer		ptr;
	}					value;

	kint				line;
	kint				column;

	struct khToken*		parent;
	struct khToken*		child[4];

	struct khToken*		prev;
	struct khToken*		next;
} khToken;

//
extern void kh_token_set_child(khToken* tk, kint index, khToken* node, kcham sib);
extern void kh_token_set_mask(khToken* tk, kint add, kint sub);
extern kcham kh_token_fold(khToken* tk);

//
extern void kh_parse_set_token(khToken* node);
extern khToken* kh_parse_get_token();
extern khToken* kh_parse_new_token(enum khTokenType type, enum khTokenRole role);
extern khToken* kh_parse_new_token_info(khToken* info, enum khTokenType type, enum khTokenRole role);
extern khToken* kh_parse_new_op(enum khTokenRole role, khToken* left, khToken* right);
extern khToken* kh_parse_copy_token(khToken* token);
extern khToken* kh_parse_link_token(khToken* left, khToken* right);
extern kchar* kh_parse_alloc_str_conv(const kchar* str);
extern klong kh_parse_check_int(const kchar* str, int base, kcham isint);
extern double kh_parse_check_float(const kchar* str, kcham isfloat);
extern int kh_parse_check_char(const kchar* str, kcham isuni);
extern kchar* kh_parse_check_str(const kchar* str);
extern kwchar* kh_parse_check_wcs(const kchar* str);
extern kint kh_parse_printf(FILE* fp, const kchar* fmt, ...);
extern void kh_parse_error(kint code, const kchar* txt);
extern void kh_parse_write_file(kFile* file);

//
KAPI kcham kh_parse_enter(const char* filename, const char* script, kcham isutf8);
KAPI void kh_parse_leave(void);

//
KAPI kint kh_compile_enter(khToken* token, const char* name, struct kRedFn** retfn);
KAPI void kh_compile_leave(void);


//////////////////////////////////////////////////////////////////////////
// for LEX & YACC
typedef struct yy_buffer_state* YY_BUFFER_STATE;
extern const kchar* khs_filename;
extern kchar* khs_text;
extern kint khs_lineno;
extern kint khs_debug;
extern kint khs_column;
extern kint khs_tabsize;
extern kcham khs_utf8;

extern YY_BUFFER_STATE khs__scan_string(const char * str);
extern YY_BUFFER_STATE khs__scan_bytes(const char *bytes, int len);
extern void khs__delete_buffer(YY_BUFFER_STATE b);
extern kint khs_lex(void);
extern kint khs_parse(void);

#endif	// __INC_KH_COMPILER_H__
